/**
 * 
 */
package fourth_assignment;

import java.util.LinkedList;
import java.util.Random;
import java.util.Vector;

import second_assignment.Consts_2nd;
import second_assignment.Manager.Client;

import first_assignment.Consts_1st.Movie;

/**
 * 
 * @author Peretz Oded, Castel Maayan, Farchy Ofir.
 */
public class DynamicManager {
    private class MovieRequest{
        Movie movie;
        boolean isFail;
        
        public MovieRequest(Movie movie, boolean fail){
            this.movie = movie;
            isFail = fail;
        }

        public Movie getMovieName() {
            return movie;
        }

        public boolean isFail() {
            return isFail;
        }
    }

    LinkedList<MovieRequest> Region_1_Latest10KRequests = new LinkedList<MovieRequest>();
    LinkedList<MovieRequest> Region_2_Latest10KRequests = new LinkedList<MovieRequest>();
    LinkedList<MovieRequest> Region_3_Latest10KRequests = new LinkedList<MovieRequest>();

    Vector<Movie> Region_1_MoviesByPopularity = new Vector<Movie>();
    Vector<Movie> Region_2_MoviesByPopularity = new Vector<Movie>();
    Vector<Movie> Region_3_MoviesByPopularity = new Vector<Movie>();

    // Movie vectors.
    Vector<Movie> recordedArray;
    Vector<Movie> recentArray;
    Vector<Movie> libraryArray;
    
    int leastRequested = 0;
    
    /**
     * @param recordedArray
     * @param recentArray
     * @param libraryArray
     */
    public DynamicManager(Vector<Movie> recordedArray,
            Vector<Movie> recentArray, Vector<Movie> libraryArray) {
        this.recordedArray = recordedArray;
        this.recentArray = recentArray;
        this.libraryArray = libraryArray;
        SetNewMovies(recordedArray);
        SetNewMovies(recentArray);
        SetNewMovies(libraryArray);
    }

    /**
     * @param newClient
     */
    public void AcceptClient(Client newClient, Movie movie) {
        MovieRequest oldMovie = null;
        switch (newClient.getRegion()) {
        case 0:
            Region_1_Latest10KRequests.addFirst(new MovieRequest(movie, false));
            if (Region_1_Latest10KRequests.size() > Consts_4th.LATEST_REQUESTS_NUM) {
                oldMovie = Region_1_Latest10KRequests.removeLast();
                oldMovie.movie.requestCount[0]--;
                oldMovie.movie.rejectCount[0] -= (oldMovie.isFail) ? 1 : 0 ;
            }
            break;
        case 1:
            Region_2_Latest10KRequests.addFirst(new MovieRequest(movie, false));
            if (Region_2_Latest10KRequests.size() > Consts_4th.LATEST_REQUESTS_NUM) {
                oldMovie = Region_2_Latest10KRequests.removeLast();
                oldMovie.movie.requestCount[1]--;
                oldMovie.movie.rejectCount[1] -= (oldMovie.isFail) ? 1 : 0 ;
            }
            break;
        case 2:
            Region_3_Latest10KRequests.addFirst(new MovieRequest(movie, false));
            if (Region_3_Latest10KRequests.size() > Consts_4th.LATEST_REQUESTS_NUM) {
                oldMovie = Region_3_Latest10KRequests.removeLast();
                oldMovie.movie.requestCount[2]--;
                oldMovie.movie.rejectCount[2] -= (oldMovie.isFail) ? 1 : 0 ;
            }
            break;
        }
        movie.requestCount[newClient.getRegion()]++;
        if (null == oldMovie) {
        	SortOrderedRequests(movie, newClient.getRegion(),true);
        }
        else {
        	SortOrderedRequests(movie, newClient.getRegion(),false);
        	SortOrderedRequests(oldMovie.movie, newClient.getRegion(),true);
        }
    }

    /**
     * @param movieName
     * @param region
     * @return
     */
    public boolean RejectClient(int region, Movie movie, boolean served) {
        MovieRequest oldMovie = null;
        switch (region) {
        case 0:
            Region_1_Latest10KRequests.addFirst(new MovieRequest(movie, true));
            if (Region_1_Latest10KRequests.size() > Consts_4th.LATEST_REQUESTS_NUM) {
                oldMovie = Region_1_Latest10KRequests.removeLast();
                oldMovie.movie.requestCount[0]--;
                oldMovie.movie.rejectCount[0] -= (oldMovie.isFail) ? 1 : 0 ;
            }
            break;
        case 1:
            Region_2_Latest10KRequests.addFirst(new MovieRequest(movie, true));
            if (Region_2_Latest10KRequests.size() > Consts_4th.LATEST_REQUESTS_NUM) {
                oldMovie = Region_2_Latest10KRequests.removeLast();
                oldMovie.movie.requestCount[1]--;
                oldMovie.movie.rejectCount[1] -= (oldMovie.isFail) ? 1 : 0 ;
            }
            break;
        case 2:
            Region_3_Latest10KRequests.addFirst(new MovieRequest(movie, true));
            if (Region_3_Latest10KRequests.size() > Consts_4th.LATEST_REQUESTS_NUM) {
                oldMovie = Region_3_Latest10KRequests.removeLast();
                oldMovie.movie.requestCount[2]--;
                oldMovie.movie.rejectCount[2] -= (oldMovie.isFail) ? 1 : 0 ;
            }
            break;
        }
        movie.requestCount[region]++;
        movie.rejectCount[region]++;
        if (null == oldMovie) {
        	SortOrderedRequests(movie, region,true);
        }
        else {
        	SortOrderedRequests(movie, region,false);
        	SortOrderedRequests(oldMovie.movie, region,true);
        }
        return (served && (movie.copies < Consts_2nd.MaxMovieCopies));// && (Consts_4th.MAX_FAILURES <= movie.rejectCount[region]));
    }

    /**
     * @param region
     * @param leastRequestedMovieIndex
     * @return
     */
    public Movie RemoveLeastRequestedMovie(int region) {//, int type) {
        leastRequested = 0;
        switch (region) {
        case 0: return Region_1_MoviesByPopularity.get(leastRequested);
        case 1: return Region_2_MoviesByPopularity.get(leastRequested);
        case 2: return Region_3_MoviesByPopularity.get(leastRequested);
        }

        return null;
    }

    public Movie getNextLeastRequestedMovie(int region) {//, int type) {
        Vector<Movie> MoviesByPopularity = null;
        switch (region) {
        case 0: MoviesByPopularity = Region_1_MoviesByPopularity;
            break;
        case 1: MoviesByPopularity = Region_2_MoviesByPopularity;
            break;
        case 2: MoviesByPopularity = Region_3_MoviesByPopularity;
            break;
        }

        if (leastRequested < MoviesByPopularity.size() - 1) {
            leastRequested++;
            return MoviesByPopularity.get(leastRequested);
        }
        return null;
    }
    
    /**
     * @param integer
     * @param string
     * @return
     */
    public Vector<String> getMoviesToDelete(Integer amount, int type, int sizeOfLeatPopClass) {
        Vector<String> moviesToDel = new Vector<String>();
        Vector<Movie> F_Vector = null;
        int index = 0;
        Movie toDelete;
        switch (type) {
        case 0: F_Vector = libraryArray;
            break;
        case 1: F_Vector = recordedArray;
            break;
        case 2: F_Vector = recentArray;
            break;
        }
        int counter = amount;
        Random generator = new Random();

        while (counter-- > 0) {
            index = generator.nextInt(sizeOfLeatPopClass);
            toDelete = F_Vector.remove(index);
            Region_2_MoviesByPopularity.removeElement(toDelete);
            Region_3_MoviesByPopularity.removeElement(toDelete);
            Region_1_MoviesByPopularity.removeElement(toDelete);
            moviesToDel.add(toDelete.movieName);
            sizeOfLeatPopClass--;
        }
        return moviesToDel;
    }

    /**
     * @param movie
     */
    private void SortOrderedRequests(Movie movie, int region, boolean flag) {
    	Vector<Movie> MoviesByPopularity = null;
        switch (region) {
        case 0: MoviesByPopularity = Region_1_MoviesByPopularity;
            break;
        case 1: MoviesByPopularity = Region_2_MoviesByPopularity;
            break;
        case 2: MoviesByPopularity = Region_3_MoviesByPopularity;
            break;
        }
        int i, j = 0;
        for ( i = 0; i < MoviesByPopularity.size(); ++i) {
            if (movie == MoviesByPopularity.get(i)) break;
        }
        if( i == MoviesByPopularity.size())
        	System.exit(0);
        for (j = i ; j > 0 ; --j) {
        	Movie tmpMovie;
        	if (MoviesByPopularity.get(j-1).requestCount[region] > MoviesByPopularity.get(j).requestCount[region]) {
        		tmpMovie = MoviesByPopularity.get(j-1);
        		MoviesByPopularity.set(j-1, MoviesByPopularity.get(j));
        		MoviesByPopularity.set(j, tmpMovie);
        	}
        	else
        		break;
        }
        
        for (j = i ; j < MoviesByPopularity.size()-1; ++j) {
        	Movie tmpMovie;
        	if (MoviesByPopularity.get(j).requestCount[region] > MoviesByPopularity.get(j+1).requestCount[region]) {
        		tmpMovie = MoviesByPopularity.get(j);
        		MoviesByPopularity.set(j, MoviesByPopularity.get(j+1));
        		MoviesByPopularity.set(j+1, tmpMovie);
        		
        	}
        	else
        		break;
        }
    }

    /**
     * @param newRecorded
     */
    public void SetNewMovies(Vector<Movie> newMovies) {
        if (null == newMovies) return;
        for (Movie movie : newMovies) {
            Region_1_MoviesByPopularity.add(movie);
            Region_2_MoviesByPopularity.add(movie);
            Region_3_MoviesByPopularity.add(movie);
        }
    }

    /**
     * 
     */
    public void ResetRequestCount() {
        for (Movie movie : Region_1_MoviesByPopularity) {
            movie.requestCount[0] = movie.requestCount[1] = movie.requestCount[2] = 0;
            movie.rejectCount[0] = movie.rejectCount[1] = movie.rejectCount[2] = 0;
        }
        Region_1_Latest10KRequests.clear();
        Region_2_Latest10KRequests.clear();
        Region_3_Latest10KRequests.clear();
    }
}
